/**
 * 计算请假时间（考虑请假类型）
 * @param {Object} options 配置选项
 * @param {Date} options.startTime 开始时间
 * @param {Date} options.endTime 结束时间
 * @param {string} options.leaveType 请假类型（'annual'年假, 'sick'病假, 'personal'事假, 'marriage'婚假等）
 * @param {Array<number>} [options.workDays=[1,2,3,4,5]] 工作日数组（0-6，0是周日）
 * @param {Array<Date>} [options.holidays=[]] 节假日数组
 * @param {Array<Date>} [options.extraWorkDays=[]] 额外工作日数组（周末加班）
 * @param {number} [options.hoursPerDay=8] 每天工作小时数
 * @param {boolean} [options.includeHalfDay=true] 是否允许半天请假
 * @param {Object} [options.leaveRules={}] 不同类型请假的具体规则
 * @returns {Object} 返回包含天数和小时数的对象
 */
function calculateLeaveTimeWithType(options: any) {
  // 参数解构与默认值
  const {
    startTime,
    endTime,
    leaveType = 'personal', // 默认事假
    workDays = [1, 2, 3, 4, 5], // 默认周一到周五
    holidays = [],
    extraWorkDays = [],
    hoursPerDay = 8,
    includeHalfDay = true,
    leaveRules = {
      annual: { minUnit: 0.125, deductWeekend: false, deductHoliday: false }, // 年假：最小单位0.125天，不扣除周末和节假日
      sick: { minUnit: 0.125, deductWeekend: true, deductHoliday: true }, // 病假：最小单位0.125天，扣除周末和节假日
      personal: { minUnit: 0.125, deductWeekend: true, deductHoliday: true }, // 事假：最小单位0.125天，扣除周末和节假日
      marriage: { minUnit: 0.125, deductWeekend: false, deductHoliday: false }, // 婚假：最小单位1小时，不扣除周末和节假日
      maternity: { minUnit: 0.125, deductWeekend: false, deductHoliday: false }, // 产假：最小单位1小时，不扣除周末和节假日
      paternity: { minUnit: 0.125, deductWeekend: false, deductHoliday: false }, // 陪产假：最小单位1小时，不扣除周末和节假日
      bereavement: { minUnit: 0.125, deductWeekend: false, deductHoliday: false } // 丧假：最小单位1天，不扣除周末和节假日
    }
  } = options;

  // 获取当前请假类型的规则
  const currentLeaveRule = leaveRules[leaveType] || leaveRules.personal;

  // 验证输入
  if (!(startTime instanceof Date) || !(endTime instanceof Date)) {
    throw new Error('开始时间和结束时间必须是Date对象');
  }
  if (startTime > endTime) {
    throw new Error('开始时间不能晚于结束时间');
  }

  // 工具函数：判断是否是同一天
  const isSameDay = (date1: Date, date2: Date): boolean => {
    return date1.getFullYear() === date2.getFullYear() &&
           date1.getMonth() === date2.getMonth() &&
           date1.getDate() === date2.getDate();
  };

  // 工具函数：判断是否是工作日
  const isWorkDay = (date: Date) => {
    const day = date.getDay();
    
    // 先检查是否是节假日
    if (holidays.some((d : Date)  => isSameDay(d, date))) {
      return false;
    }
    
    // 检查是否是额外工作日
    if (extraWorkDays.some((d: Date) => isSameDay(d, date))) {
      return true;
    }
    
    // 检查是否是正常工作日
    return workDays.includes(day);
  };

  // 根据请假类型判断是否应该计算某天
  const shouldCountDay = (date: Date) => {
    const day = date.getDay();
    const isHoliday = holidays.some((d:Date) => isSameDay(d, date));
    const isExtraWorkDay = extraWorkDays.some((d: Date) => isSameDay(d, date));
    
    // 额外工作日总是计算
    if (isExtraWorkDay) return true;
    
    // 如果是节假日
    if (isHoliday) {
      return !currentLeaveRule.deductHoliday;
    }
    
    // 如果是周末
    if (!workDays.includes(day)) {
      return !currentLeaveRule.deductWeekend;
    }
    
    return true;
  };

  // 工具函数：计算一天内的实际工作时间（排除午休）
  const calculateDayWorkingHours = (dayStartTime: Date, dayEndTime: Date, workStartHour = 9, workEndHour = 18) => {
    const workStart = new Date(dayStartTime.getFullYear(), dayStartTime.getMonth(), dayStartTime.getDate(), workStartHour, 0, 0);
    const workEnd = new Date(dayStartTime.getFullYear(), dayStartTime.getMonth(), dayStartTime.getDate(), workEndHour, 0, 0);
    const lunchStart = new Date(dayStartTime.getFullYear(), dayStartTime.getMonth(), dayStartTime.getDate(), 12, 0, 0);
    const lunchEnd = new Date(dayStartTime.getFullYear(), dayStartTime.getMonth(), dayStartTime.getDate(), 13, 0, 0);
    
    // 确保时间在工作时间范围内
    const actualStart = dayStartTime < workStart ? workStart : dayStartTime;
    const actualEnd = dayEndTime > workEnd ? workEnd : dayEndTime;
    
    if (actualStart >= actualEnd) return 0;
    
    let totalHours = (actualEnd.getTime() - actualStart.getTime()) / (1000 * 60 * 60);
    
    // 如果请假时间跨越午休时间，需要减去午休时间
    if (actualStart < lunchEnd && actualEnd > lunchStart) {
      const lunchOverlapStart = actualStart > lunchStart ? actualStart : lunchStart;
      const lunchOverlapEnd = actualEnd < lunchEnd ? actualEnd : lunchEnd;
      const lunchOverlapHours = (lunchOverlapEnd.getTime() - lunchOverlapStart.getTime()) / (1000 * 60 * 60);
      totalHours -= lunchOverlapHours;
    }
    
    return Math.max(0, totalHours);
  };

  // 如果是同一天请假
  if (isSameDay(startTime, endTime)) {
    if (!shouldCountDay(startTime)) {
      return { days: 0, hours: 0, leaveType: leaveType };
    }
    
    // 使用新的计算函数，排除午休时间
    let hours = calculateDayWorkingHours(startTime, endTime);
    
    // 根据最小请假单位调整
    if (currentLeaveRule.minUnit >= 1) {
      hours = Math.ceil(hours / hoursPerDay) * hoursPerDay;
    } else if (currentLeaveRule.minUnit === 0.5) {
      hours = Math.ceil(hours / (hoursPerDay / 2)) * (hoursPerDay / 2);
    } else if (currentLeaveRule.minUnit === 0.125) {
      // 1小时最小单位，向上取整到最近的小时，但不超过每天工作小时数
      hours = Math.min(Math.ceil(hours), hoursPerDay);
    }
    
    return {
      days: parseFloat((hours / hoursPerDay).toFixed(2)),
      hours: parseFloat(hours.toFixed(2)),
      leaveType: leaveType
    };
  }

  // 跨天请假的情况
  // 计算总的请假时间（小时）
  const totalMs = endTime.getTime() - startTime.getTime();  
  const totalHours = totalMs / (1000 * 60 * 60);
  
  // 计算涉及的日期范围
  const startDate = new Date(startTime.getFullYear(), startTime.getMonth(), startTime.getDate());
  const endDate = new Date(endTime.getFullYear(), endTime.getMonth(), endTime.getDate());
  
  let workingHours = 0;
  let currentDate = new Date(startDate);
  
  // 遍历每一天，计算实际工作日的小时数
  while (currentDate <= endDate) {
    if (shouldCountDay(currentDate)) {
      if (isSameDay(currentDate, startDate) && isSameDay(currentDate, endDate)) {
        // 同一天（这种情况上面已经处理了，这里是保险）
        workingHours += calculateDayWorkingHours(startTime, endTime);
      } else if (isSameDay(currentDate, startDate)) {
        // 开始日：从开始时间到工作日结束（18:00），排除午休时间
        const workEndTime = new Date(currentDate);
        workEndTime.setHours(18, 0, 0, 0); // 工作日结束时间18:00
        
        if (startTime < workEndTime) {
          const dayHours = calculateDayWorkingHours(startTime, workEndTime);
          // 按1小时最小单位向上取整
          const actualHours = Math.ceil(dayHours);
          workingHours += Math.min(actualHours, hoursPerDay);
        }
      } else if (isSameDay(currentDate, endDate)) {
        // 结束日：从工作日开始（9:00）到结束时间，排除午休时间
        const workStartTime = new Date(currentDate);
        workStartTime.setHours(9, 0, 0, 0); // 工作日开始时间9:00
        
        if (endTime > workStartTime) {
          const workEndTime = new Date(currentDate);
          workEndTime.setHours(18, 0, 0, 0); // 工作日结束时间18:00
          
          const actualEndTime = endTime > workEndTime ? workEndTime : endTime;
          const dayHours = calculateDayWorkingHours(workStartTime, actualEndTime);
          workingHours += dayHours;
        }
      } else {
        // 中间的完整工作日（9小时工作时间 - 1小时午休 = 8小时）
        workingHours += hoursPerDay;
      }
    }
    
    currentDate.setDate(currentDate.getDate() + 1);
  }

  // 更简单的计算方式：按实际时间跨度计算
  // 如果总时间跨度是24小时的整数倍，直接按天数计算
  if (totalHours % 24 === 0) {
    const days = totalHours / 24;
    let finalDays = days;
    let finalHours = days * hoursPerDay;
    
    // 根据最小请假单位调整
    if (currentLeaveRule.minUnit >= 1) {
      finalDays = Math.ceil(finalDays);
      finalHours = finalDays * hoursPerDay;
    } else if (currentLeaveRule.minUnit === 0.5) {
      finalDays = Math.round(finalDays * 2) / 2;
      finalHours = finalDays * hoursPerDay;
    } else if (currentLeaveRule.minUnit === 0.125) {
      // 1小时最小单位，对于24小时整数倍的情况，保持原来的天数计算
      // 但小时数需要按1小时向上取整
      finalHours = Math.ceil(finalHours);
      finalDays = finalHours / hoursPerDay;
    }
    
    return {
      days: parseFloat(finalDays.toFixed(2)),
      hours: parseFloat(finalHours.toFixed(2)),
      leaveType: leaveType
    };
  }

  // 对于非整天的情况，使用修正后的逻辑
  let totalDays = workingHours / hoursPerDay;
  
  // 根据最小请假单位调整结果
  if (currentLeaveRule.minUnit >= 1) {
    totalDays = Math.ceil(totalDays);
    workingHours = totalDays * hoursPerDay;
  } else if (currentLeaveRule.minUnit === 0.5) {
    // 四舍五入到最近的0.5
    totalDays = Math.round(totalDays * 2) / 2;
    workingHours = totalDays * hoursPerDay;
  } else if (currentLeaveRule.minUnit === 0.125) {
    // 1小时最小单位，按小时向上取整
    workingHours = Math.ceil(workingHours);
    totalDays = workingHours / hoursPerDay;
  }

  return {
    days: parseFloat(totalDays.toFixed(2)),
    hours: parseFloat(workingHours.toFixed(2)),
    leaveType: leaveType
  };
}

// // 使用示例
// const startTime = new Date('2023-05-15T09:00:00');
// const endTime = new Date('2023-05-18T17:00:00');

// // 节假日
// const holidays = [new Date('2023-05-17')];

// // 示例1: 年假（通常不计入节假日和周末）
// const annualLeave = calculateLeaveTimeWithType({
//   startTime,
//   endTime,
//   leaveType: 'annual',
//   holidays
// });
// console.log('年假:', annualLeave);

// // 示例2: 病假（通常计入所有日历日）
// const sickLeave = calculateLeaveTimeWithType({
//   startTime,
//   endTime,
//   leaveType: 'sick',
//   holidays
// });
// console.log('病假:', sickLeave);

// // 示例3: 婚假（通常有特殊计算规则）
// const marriageLeave = calculateLeaveTimeWithType({
//   startTime: new Date('2023-05-15T09:00:00'),
//   endTime: new Date('2023-05-19T17:00:00'),
//   leaveType: 'marriage',
//   holidays
// });
// console.log('婚假:', marriageLeave);

export default calculateLeaveTimeWithType;